// 使用一个第三方包，为了判断 /scores/:id 格式的动态路由
const { match } = require('path-to-regexp');

// 导出一个函数，并返回一个中间件函数
// 导出函数是为了使用 config.default.js 中，对中间件的配置信息
module.exports = (options) => {
    // 返回一个授权中间件
    return async (ctx, next) => {
        // 如果在白名单中的请求，就直接放行
        if (options.whiteList.includes(ctx.path)) {
            await next();
            // 如果不是白名单中的请求，就需要校验 token
        } else {
            // 获取请求 header 中的 token
            let token = ctx.headers.token;
            // 如果没有 token，就返回 401 表示用户没有登录
            if (!token) {
                ctx.body = {
                    code: 401,
                    message: '缺少 token 字段',
                };
                return;
            }
            // 校验 token 是不是服务器签发的
            try {
                // 如果是服务器签发的，就会校验成功，并返回 token 中包含的用户信息
                ctx.profile = ctx.helper.checkToken(token);
            } catch (error) {
                // 如果不是服务器签发的，或者是前端修改后的 token，或者是过期的 token，就都会报错
                // 在这里捕获错误，并响应提示前台
                // Token 过期错误提示
                if (error.name === 'TokenExpiredError') {
                    ctx.body = {
                        code: 401,
                        message: 'token过期',
                    };
                    return;
                }
                // 无效 Token 错误提示
                if (error.name === 'JsonWebTokenError') {
                    ctx.body = {
                        code: 401,
                        message: '无效的token',
                    };
                    return;
                }
            }
            // 校验接口权限
            let aclList = await ctx.service.user.readAclsByUid(ctx.profile.uid);
            console.log('aclList', aclList);
            let isAllow = aclList.some((item) => {
                let instance = match(item.path, {
                    decode: decodeURIComponent,
                });
                return instance(ctx.path) && ctx.method === item.method;
            });
            if (!isAllow) {
                ctx.body = {
                    code: 403,
                    message: '你无权请求该接口',
                };
                return;
            }
            // 所有校验都通过后，就继续向下执行
            await next();
        }
    };
};
